﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EnvDTE;

namespace ScaffoldIt
{
    static class CodeModelHelpers
    {
        public static IEnumerable<CodeClass> GetClasses(this CodeElements elements)
        {
            return GetClasses(elements, null);
        }

        public static IEnumerable<CodeClass> GetClasses(this CodeElements elements, Predicate<CodeClass> filter)
        {
            foreach (CodeElement codeelt in elements)
            {
                if (codeelt is CodeClass)
                {
                    var eltclass = (CodeClass)codeelt;
                    if (filter == null || filter(eltclass))
                        yield return eltclass;
                }

                CodeElements childs = null;
                try
                {
                    childs = codeelt.Children;
                    int total = childs.Count;
                }
                catch
                {
                    childs = null;
                }

                if (childs != null)
                {
                    foreach (var class2 in childs.GetClasses(filter))
                    {
                       yield return class2;
                    }
                }
            }
        }

        /*
        public static IEnumerable<KeyValuePair<string, string>> PublicFields(this CodeClass codeClass)
        {
            foreach (CodeElement elt in codeClass.Members)
            {
                if (elt is CodeProperty)
                {
                    var codeProp = elt as CodeProperty;
                    if (codeProp.Access == vsCMAccess.vsCMAccessPublic)
                    {
                        yield return new KeyValuePair<string, string>(codeProp.Name, codeProp.Type.AsString);
                    }
                }
            }
        }*/

        public static IEnumerable<CodeProperty> PublicProperties(this CodeClass codeClass)
        {
            var properties = new List<string>();
            return PublicProperties(codeClass, properties);
        }

        private static IEnumerable<CodeProperty> PublicProperties(this CodeClass codeClass, List<string> properties)
        {
            foreach (var elt in codeClass.Members)
            {
                if (elt is CodeProperty)
                {
                    var codeProp = elt as CodeProperty;
                    if (codeProp.Access == vsCMAccess.vsCMAccessPublic && !properties.Contains(codeProp.Name))
                    {
                        properties.Add(codeProp.Name);
                        yield return codeProp;
                        //yield return new KeyValuePair<string, string>(codeProp.Name, codeProp.Type.AsString);
                    }
                }
            }

            List<CodeProperty> baseClassProps = new List<CodeProperty>();
            try
            {
                var baseclasses = codeClass.Bases.GetClasses();
                foreach (var baseclass in baseclasses)
                {
                    baseClassProps.AddRange(baseclass.PublicProperties(properties));
                }
            }
            catch
            {
            }

            if (baseClassProps.Count > 0)
            {
                foreach (var baseClassProp in baseClassProps)
                {
                    yield return baseClassProp;
                }
            }
        }

        public static IEnumerable<CodeProperty> NonPublicProperties(this CodeClass codeClass)
        {
            foreach (var elt in codeClass.Members)
            {
                if (elt is CodeProperty)
                {
                    var codeProp = elt as CodeProperty;
                    if (codeProp.Access != vsCMAccess.vsCMAccessPublic)
                    {
                        yield return codeProp;
                        //yield return new KeyValuePair<string, string>(codeProp.Name, codeProp.Type.AsString);
                    }
                }
            }

            List<CodeProperty> baseClassProps = new List<CodeProperty>();
            try
            {
                var baseclasses = codeClass.Bases.GetClasses();
                foreach (var baseclass in baseclasses)
                {
                    baseClassProps.AddRange(baseclass.NonPublicProperties());
                }
            }
            catch
            {
            }

            if (baseClassProps.Count > 0)
            {
                foreach (var baseClassProp in baseClassProps)
                {
                    yield return baseClassProp;
                }
            }
        }
    }
}
